import ctypes
import threading

lib = ctypes.cdll.LoadLibrary(r'B:\codes\C_Cpp\DMuse\ReaperRemoteMMAP.dll')

send_tagname = b'rpr_r2c_1'
recv_tagname = b'rpr_c2r_1'
lib.Listen(ctypes.c_char_p(send_tagname), ctypes.c_char_p(recv_tagname), 10240, 10)

last_msg_id = ''
channels = [None] * 10


def clear_send(ch):
    lib.ClearSend(ch)


def clear_recv(ch):
    lib.ClearRecv(ch)


def send(chan, obj):
    b2 = obj.encode('utf-8')
    # print('send:', b2, len(b2))
    lib.PushMsg(chan, b2, len(b2))


def recv(chan):
    s = b''
    p = ctypes.c_char_p(s)
    lib.GetMsg(chan, p)
    # print('recv:', chan, p.value)
    try:
        s = str(p.value, encoding='utf-8')
        return s
    except SyntaxError:
        return ''
    except Exception as e:
        return 'Error: ' + str((e, chan, p.value))


class Fetcher(threading.Thread):
    def __init__(self, msg):
        super().__init__()
        self.msg = msg
        self.i = -1

    def run(self):
        for i in range(len(channels)):
            if not channels[i]:
                lib.ClearSend(i)
                lib.ClearRecv(i)
                send(i, self.msg)
                obj = None
                while obj is None and obj not in channels:
                    obj = recv(i)
                channels[i] = obj
                self.i = i
                return

    def get(self):
        obj = channels[self.i]
        channels[self.i] = None
        return obj


def fetch(msg, dtype='str', until_not_none=True):
    obj = 'None'
    while obj == 'None':
        fetcher = Fetcher(msg)
        fetcher.start()
        fetcher.join()
        obj = str(fetcher.get())
        if dtype == 'int':
            if obj is not None:
                obj = int(obj)
            else:
                obj = -1
            break
        elif dtype == 'float':
            if obj != 'None':
                obj = float(obj)
            else:
                obj = 0.
            break
        elif not until_not_none:
            break
    return obj



def RPR_TrackFX_GetFXName(tr, i, param, value):
    return fetch(f"RPR_TrackFX_GetFXName('{tr}', {i}, '{param}', {value})")


def RPR_TrackFX_GetCount(tr):
    return fetch(f"RPR_TrackFX_GetCount('{tr}')", dtype='int')


def RPR_TrackFX_GetParamName(tr, i, id_, a, b):
    return fetch(f"RPR_TrackFX_GetParamName('{tr}', {i}, {id_}, '{a}', {b})")


def RPR_TrackFX_GetParamNormalized(tr, i, id_):
    return fetch(f"RPR_TrackFX_GetParamNormalized('{tr}', {i}, {id_})", dtype='float')


def RPR_GetLastTouchedTrack():
    return fetch(f"RPR_GetLastTouchedTrack()")

